/*
 * GeoVISTA Center (Penn State, Dept. of Geography)
 * Copyright (c), 2003-2011,  Jin Chen and Alan M. MacEachren, GeoVISTA Center, Penn State University
 * All Rights Researved.
 *
 * This library is developed and distributed for free usage,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * You can redistribute and/or modify it under the terms of the
 * Simplified BSD License
 *
 *
 *
 *
 *
 *
 *
 *
 * @Original Author: jin Chen
 * @date: Oct 23, 2003$
 * @version: 1.0
 */
package edu.psu.geovista.app.dataloader.v1.components;

import edu.psu.geovista.app.dataloader.DfMetaData;
import edu.psu.geovista.app.dataloader.v1.config.model.DfVariableData;
import edu.psu.geovista.app.dataloader.v1.config.model.ModelUtils;
import edu.psu.geovista.app.dataloader.v1.config.model.VariableData;
import edu.psu.geovista.app.dataloader.v1.gui.DataSelectPane;
import edu.psu.geovista.app.pcp.toolkits.selectcontrol.SelectItemsPane;
import edu.psu.geovista.app.pcp.toolkits.table.ConfigureTableModel;
import edu.psu.geovista.common.awt.event.dataloading.TSDataListener;
import edu.psu.geovista.ui.dataloader.common.ConfigurePropSavor;
import edu.psu.geovista.ui.dataloader.common.FileLoadingPane;
import edu.psu.geovista.ui.dataloader.event.LoadDataListener;
import edu.psu.geovista.ui.event.DataSetListener;

import javax.swing.*;
import java.awt.*;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.*;

public abstract class SingleDataLoader extends JPanel{
    public static final boolean DEBUG=false;
     public static final String DIALOG_TITLE_CAUTION = "Caution";
    public static final Color TEXT_COLOR=new java.awt.Color(83, 109, 165);
    protected DataSelectPane dataList;
    protected FileLoadingPane dataPathPane;
    protected edu.psu.geovista.app.dataloader.v1.components.DefaultNCIDataSource dataSource;
    protected edu.psu.geovista.app.dataloader.v1.components.DataAssembler dataAssembler;
    protected LoadDataListener ldl;

    protected VariableData datainfo;

//listen to the instrution to load the data, usually listen to "load data" button

    public SingleDataLoader(NCIDataSource dataSource) {
        if(dataSource==null)
            this.dataSource=new edu.psu.geovista.app.dataloader.v1.components.DefaultNCIDataSource();
        else
            this.dataSource =(edu.psu.geovista.app.dataloader.v1.components.DefaultNCIDataSource) dataSource;
        dataAssembler=new edu.psu.geovista.app.dataloader.v1.components.DataAssembler(this.dataSource);
        setup();

    }

    public SingleDataLoader() {
        setup();
    }

   /*******************************************************************************************************
     *              services
     *******************************************************************************************************/

   public void  loadInteractively() {

   }

   public String [] getSelectAttributeNames(){
        Object[] cols= this.dataList.getColumnValues(0, SelectItemsPane.TABLE_RIGHT );
        String [] names=new String[cols.length ];
        for (int i=0;i<names.length ;i++){
            names[i]=(String) cols[i];

        }
        return names;
    }
    public void selectAttributes(String [] names) {
         this.dataList.selectRecord(names);//selectedAttributes(names);
    }
    public void selectAllAttributes() {
         dataList.selectAllAttributes() ;
    }
    public void deSelectAllAttributes() {
         dataList.deSelectAllAttributes();
    }
    /**
     * set data info( paths, selected attr) based on project setting
     * automatically load data and selected attributes
     * @param datainfo
     */
    public void setDataInfo(VariableData datainfo){
            assert(datainfo!=null): "Not accept null value";
            //this.datainfo =datainfo;
         //1. data path
            //Properties paths= ModelUtils.getPaths(datainfo);
            java.util.List paths= ModelUtils.getPaths(datainfo);
            if(paths!=null&&paths.size() >0){
                Properties pp = DfVariableData.toProperties(paths);
                this.setFileLoaderValues(pp); //set paths
            }
            else{
                this.setAllFileLoaderValues("");
            }
           /* //3. load data, if path not correct =>exception
            boolean success=this.loadDataInfo();
            //4. if data is loaded, selected attributes
            if(success){
                String [] attrs=ConfigureProcessor.getSelectAttributeNames(datainfo);
                this.dataList.setSelectedAttributes(attrs);
            }*/

    }
    public boolean autoSelectAttributes() throws Exception{
        //3. load data, if path not correct =>exception
            
            boolean success=this.loadDataInfo();
            //4. if data is loaded, selected attributes
            if(success){
                String [] attrs=new String[0];
                if(datainfo!=null){//for new project datainfo==null
                    attrs=ModelUtils.getSelectAttributeNames(datainfo);
                }
                if(attrs!=null&&attrs.length >0){
                    this.dataList.selectRecord(attrs);// selectedAttributes(attrs);
                }
                else{
                    dataList.selectAllAttributes() ;
                }
            }
         return success;
    }
    public  abstract boolean loadDataInfo() throws Exception;
    public void fillProjectInfo(VariableData datainfo){
        Properties ps=this.getFileLoaderValues() ;
        String[] attrs=this.getSelectAttributeNames() ;

        ModelUtils.setPaths(datainfo,ps);
        ModelUtils.setSelectAttributeNames(datainfo,attrs);
    }


    /*******************************************************************************************************
     *                supports
     *******************************************************************************************************/
   /* protected JPanel getPathsPane(){

    }
    protected void showPane(JPanel pane,String title){
        JDialog dlg=this.getPathDialog(title) ;
        dlg.getContentPane().add(pane );
        dlg.show();
        dlg.dispose() ;
    }

    protected JDialog getPathDialog(String title) {

           JDialog dlg=new JOptionPane().createDialog(this,title);
                dlg.setModal(true);
                dlg.getContentPane().removeAll() ;
                dlg.setResizable(true);
                dlg.setSize(new Dimension(600,600));
                dlg.setLocation(100,100);
                dlg.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE );

        return dlg;
    }
    */
    /*******************************************************************************************************
     *                setup
     *******************************************************************************************************/
    protected  void setup(){
         initComponents();
         this.setLayout(new BorderLayout());
         this.add(dataPathPane,BorderLayout.NORTH );
         this.add(dataList);
    }
    public void reset() {
        this.setAllFileLoaderValues("");
        this.dataList.initLeftTable() ;
    }
    /**
     *
     * @param file    this is the initial directory which displayed by filechooser when the Open button is click
     */
    public void setRoot(File file) {
        this.dataPathPane.setRoot(file);
    }
    /**
     *  Extented by subclass. Functions
     *  1. specify the names of path in pathPane
     *  2. Based on the specified name, assign paths to dataAssembler which is application-specific
     *  3. populate dataList with names of data's attribute upon dataloading complete
     *
     */
    public abstract void initComponents();
    /**
     * Extend by subclass
     * setup listpane
     * @return
     */
    protected   abstract DataSelectPane setupListPane(DataSelectPane  dataP);
    /**
     * load data file and  list all the attribute names
     * @param obFile
     * @param metaF
     * @param shpFile  if shpFile is null, shp file is to be treated as non-mandatory ( useful for standalone pcp and time series)
     *                 otherwise, it means the shp file is mandatory
     * @return   true if load data successfully
     */
    protected boolean firstProcessFiles(String obFile,String metaF,String shpFile) throws Exception {
          try {
                     dataAssembler.loadFiles(obFile, metaF,shpFile);
                 }
                 catch (WarningException e) {
                        String msg=e.getMessage() ;
                        JOptionPane.showMessageDialog(this,msg,DIALOG_TITLE_CAUTION,JOptionPane.WARNING_MESSAGE);
                        //JOptionPane.showMessageDialog(this,msg);
                 }
                 catch (Exception e) {
                     /*String msg=e.getMessage() ;
                     JOptionPane.showMessageDialog(this,msg);

                     if(DEBUG)
                        e.printStackTrace();  //To change body of catch statement use Options | File Templates.
                     return false;
                        */
                    throw e;

                 }

        setDataList();
        return true;
    }
    /**
     * provide dataList with data names (and their description)
     *
     */
    protected void setDataList() {



        //1. get names and their descriptions
         /*
        Object[] IdCol = metaModel.getColumn(EstatMetaData.MetaFile_ColumnHeader);
        Object[] descCol = metaModel.getColumn(EstatMetaData.MetaFile_Desc);
        Object[] ctgACol = metaModel.getColumn(EstatMetaData.MetaFile_CATEGORY_A);
         ConfigureTableModel model=new ConfigureTableModel();
        model.addColumn(DataSelectPane.Col_Name,IdCol);
        model.addColumn(DataSelectPane.Col_Desc,descCol);
         
         
         
        */
        String[] attrs = dataAssembler.getAttributeNameList();//It get a name list without "FIPS"
        Arrays.sort(attrs);//sort the names
        Map descs = dataAssembler.getColumnDescription();
        DfMetaData metaData = (DfMetaData) dataAssembler.getMetaData();
        Hashtable ctga = metaData.getMappingForColumn(DfMetaData.MetaFile_ColumnHeader, DfMetaData.MetaFile_CATEGORY_A);

        


        //2. convert the data into a vector that contain vectors, each of which contain a name and a description
        Vector data=new Vector();
        for (int i=0;i<attrs.length ;i++){
             String desc="";
            String name = attrs[i];
            Object o=descs.get(name);
             if(o!=null)
                desc=(String) o;
            String  ctg = (String) ctga.get(name);
            Vector record=new Vector();
             record.add(name); record.add(desc);
             if(ctg!=null) record.add(ctg);
             data.add(record);

        }

        //3. define column name
        Vector colNames=new Vector();
        colNames.add(DataSelectPane.Col_Name);
        colNames.add(DataSelectPane.Col_Desc);
        if(ctga!=null&&ctga.size() >0){
           colNames.add(DataSelectPane.Col_Category); //add Category column
        }

        //4. make a table model using the vector
        ConfigureTableModel model=new ConfigureTableModel();
        model.setDataVector(data,colNames);


        dataList.setData(model);


    }



    /**
     * programming click on apply button
     */
    public void doApply() throws Exception {
      this.dataList.doApply() ;

    }


    /**
     * add any JComponent to the controlPane. The JPanel only contain the component's GUI
     * User are responsible to implement its logic
     * @param
     */
    public void addControlComponent(JComponent comp) {
        this.dataPathPane.addComponentToControlPane(comp);
    }

    public void setDataList(DataSelectPane dataList) {
        this.dataList = dataList;
    }

    public void setDataPathPane(FileLoadingPane dataPathPane) {
        this.dataPathPane = dataPathPane;
    }

     public Properties getFileLoaderValues() {
        return this.dataPathPane.getFileLoaderValues() ; //FileLoadingPane
    }
     /**
      * set file paths
      * @param fileLoaderValues
      */
     public void setFileLoaderValues(Properties fileLoaderValues){
        this.dataPathPane.setFileLoaderValues(fileLoaderValues);
    }

    public void setAllFileLoaderValues(String  value) {
        this.dataPathPane.setAllFileLoaderValues(value);
    }
    /**
     * set external propertySavor
     * @param propertySavor
     */
     public void setPropertySavor(ConfigurePropSavor propertySavor) {
        this.dataPathPane.setPropertySavor(propertySavor);
    }
    /**
     * loading property data into FileLoadingPane
     */
    public void populateDataPath() {
        this.dataPathPane.load() ;
    }

    /*******************************************************************************************************
     *                event
     *******************************************************************************************************/
    public void addLoadDataListner(LoadDataListener ll) {
        this.dataPathPane.addLoadDataListner(ll);
    }

    /**
     * five data event upon loading data complete
     * The data event contain data in Object[] format
     * @param l
     */
    public void addDataChangeListener(DataSetListener l) {
	dataAssembler.addDataSetListener( l);
  }

  /**
   * removes an DataSetListener from the button
   */
  public void removeDataChangeListener(DataSetListener l) {
	dataAssembler.removeDataSetListener(l);
  }
  public void addTsDataListener(TSDataListener l) {
	dataAssembler.addTsDataListener(l);
  }

  /**
   * removes an DataSetListener from the button
   */
  public void removeTsDataListener(TSDataListener l) {
	  dataAssembler.removeTsDataListener(l);
  }
   /**
    * whenever a file is open by file load pane, u get the event, contain info on file path
     * @param l
    */
   public void addFileOpenListener(PropertyChangeListener l){
       this.dataPathPane.addPropertyChangeListener(l);
   }

  /*******************************************************************************************************
   *                properties
   *******************************************************************************************************/
    public DataSelectPane getDataList() {
        return dataList;
    }

    public FileLoadingPane getDataPathPane() {
        return dataPathPane;
    }


}
